﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenCLNet;

namespace GPUCaster
{
    class Volume
    {
        private readonly short[] _volumeData;
        private readonly int _size;
        private readonly OpenCLManager _openClManager;
        private Mem _volumeDataBuffer;

        /// <summary>
        /// Create a new Volume with (size X size X size) dimension
        /// </summary>
        /// <param name="size"></param>
        /// <param name="openClManager"></param>
        public Volume(int size, OpenCLManager openClManager)
        {
            _volumeData = new short[size * size * size];
            _size = size;
            _openClManager = openClManager;            

        }

        /// <summary>
        /// Get the volume data of the given position
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public short GetValue(int x, int y, int z)
        {
            if(x<0 || x >=_size)
            {
                throw new ArgumentOutOfRangeException("x");
            }
            if (y < 0 || y >= _size)
            {
                throw new ArgumentOutOfRangeException("y");
            }
            if (z < 0 || z >= _size)
            {
                throw new ArgumentOutOfRangeException("z");
            }
            return _volumeData[x * _size * _size + y * _size + z];
        }

        /// <summary>
        /// Set the volume data to value at the given position
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        /// <param name="value"></param>
        public void SetValue(int x, int y, int z, short value)
        {
            if (x < 0 || x >= _size)
            {
                throw new ArgumentOutOfRangeException("x");
            }
            if (y < 0 || y >= _size)
            {
                throw new ArgumentOutOfRangeException("y");
            }
            if (z < 0 || z >= _size)
            {
                throw new ArgumentOutOfRangeException("z");
            }
            _volumeData[x * _size * _size + y * _size + z] = value;
        }

        public unsafe Mem GetBuffer()
        {
            if (_volumeDataBuffer == null)
            {
                fixed (short* volumeDataPointer = _volumeData)
                    _volumeDataBuffer = _openClManager.Context.CreateBuffer(MemFlags.COPY_HOST_PTR, _volumeData.Count() * 2, new IntPtr(volumeDataPointer));
            }
            return _volumeDataBuffer;
        }

        public int GetSize()
        {
            return _size;
        }      
    }
}
